/**
 * 文件名：StringUtil.java
 * 创建日期：  2016年7月15日
 * 作者：      lzx
 * 版权所有(C) 2016-2017 深圳市百立特信息技术有限公司
 * 保留所有权利.
 */
package com.shop.common;

import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Blob;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 字符串处理
 */
public class StringUtil extends org.apache.commons.lang3.StringUtils {
	private static final Logger logger = LoggerFactory.getLogger(StringUtil.class);

	/**
	 * 换行符
	 */
	public static final String CRIF = System.getProperty("line.separator");

	/**
	 * 操作系统名称
	 */
	public static final String OS = System.getProperty("os.name");

	/**
	 * 文件分隔符
	 */
	public static final String FILE_SEPARATOR = System.getProperty("file.separator");

	/**
	 * 空白字符串
	 */
	public static final String EMPTY = "";

	/**
	 * null
	 */
	public static final String NULL = null;

	/**
	 * 
	 * nvl:(去null，去空白字符串). <br/>
	 * 
	 * @param str
	 * @return String
	 * @since 1.0
	 */
	public static String nvl(String str) {
		if (str != null && !str.trim().equals("")) {
			return str.trim();
		}
		return "";
	}

	/**
	 * 
	 * createEmptyString:(得到指定长度的空白字符串). <br/>
	 * 
	 * @param num
	 * @return String
	 * @since 1.0
	 */
	public static String createEmptyString(int num) {
		String str = "";
		while (num > 0) {
			str += " ";
			num--;
		}
		return str;
	}

	/**
	 * 
	 * countChineseNumber:(判断有几个中文字符). <br/>
	 * 
	 * @param str
	 * @return int
	 * @since 1.0
	 */
	public static int countChineseNumber(String str) {
		String temp = null;
		Pattern p = Pattern.compile("[\u4E00-\u9FA5]+");
		Matcher m = p.matcher(str);
		int count = 0;
		while (m.find()) {
			temp = m.group(0);
			count += temp.length();
		}
		return count;
	}

	/**
	 * 
	 * countByteLength:(得到字符串的字节长度， 中文 占2个字节). <br/>
	 * 
	 * @param source 字符串
	 * @return 字符串的字节长度
	 * @since 1.0
	 */
	public static int countByteLength(String source) {
		int len = 0;
		for (int i = 0; i < source.length(); i++) {
			char c = source.charAt(i);
			int highByte = c >>> 8;
			len += highByte == 0 ? 1 : 2;
		}
		return len;
	}

	/**
	 * 
	 * isNull:(为null 或 ""). <br/>
	 * 
	 * @param str
	 * @return boolean
	 * @since 1.0
	 */
	public static boolean isNull(String str) {
		if (str == null || "".equals(str)) {
			return true;
		}
		return false;
	}

	/**
	 * 
	 * isEmpty:(为null 或 "" 或 空白字串). <br/>
	 * 
	 * @param str
	 * @return boolean
	 * @since 1.0
	 */
	public static boolean isEmpty(String str) {
		return str == null || str.trim().isEmpty();
	}

	/**
	 * 功能：判断字符串是否为数字
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumeric(String str) {
		Pattern pattern = Pattern.compile("[0-9]*");
		Matcher isNum = pattern.matcher(str);
		if (isNum.matches()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 
	 * equals:(检查两个字符串是否相等). <br/>
	 * 
	 * @param s1 字符串A
	 * @param s2 字符串B
	 * @return true 如果两个字符串相等,且两个字符串均不为null
	 * @since 1.0
	 */
	public static boolean equals(String s1, String s2) {
		return s1 == null ? s2 == null : s1.equals(s2);
	}

	/**
	 * 
	 * equalsIgnoreCase:(检查两个字符串的忽略大小写后是否相等.). <br/>
	 * 
	 * @param s1 字符串A
	 * @param s2 字符串B
	 * @return true 如果两个字符串忽略大小写后相等,且两个字符串均不为null
	 * @since 1.0
	 */
	public static boolean equalsIgnoreCase(String s1, String s2) {
		return s1 == null ? s2 == null : s1.equalsIgnoreCase(s2);
	}

	/**
	 * 
	 * Blob2String:(blob二进制流转字符串). <br/>
	 * 
	 * @param blob
	 * @return
	 * @since 1.0
	 */
	public static String Blob2String(Blob blob) {
		String result = "";
		try {
			ByteArrayInputStream content = (ByteArrayInputStream) blob.getBinaryStream();
			byte[] byte_data = new byte[content.available()];
			content.read(byte_data, 0, byte_data.length);
			result = new String(byte_data);
		} catch (Exception ex) {
			logger.error("error=", ex);
		}
		return result;
	}

	/**
	 * 
	 * replace:(高效字符替换). <br/>
	 * 
	 * @param strSource 源字符串
	 * @param strFrom 待替换旧字符
	 * @param strTo 替换为新字符
	 * @return
	 * @since 1.0
	 */
	public static String replace(String strSource, String strFrom, String strTo) {
		if (strSource == null) {
			return null;
		}
		int i = 0;
		if ((i = strSource.indexOf(strFrom, i)) >= 0) {
			char[] cSrc = strSource.toCharArray();
			char[] cTo = strTo.toCharArray();
			int len = strFrom.length();
			StringBuffer buf = new StringBuffer(cSrc.length);
			buf.append(cSrc, 0, i).append(cTo);
			i += len;
			int j = i;
			while ((i = strSource.indexOf(strFrom, i)) > 0) {
				buf.append(cSrc, j, i - j).append(cTo);
				i += len;
				j = i;
			}
			buf.append(cSrc, j, cSrc.length - j);
			return buf.toString();
		}
		return strSource;
	}

	/**
	 * 
	 * revert:(字串逆排). <br/>
	 * 
	 * @param src
	 * @return String
	 * @since 1.0
	 */
	public static String revert(String src) {
		if (isEmpty(src))
			return "";
		StringBuffer result = new StringBuffer();
		for (int i = src.length() - 1; i >= 0; i--) {
			result.append(src.charAt(i));
		}
		return result.toString();
	}

	/**
	 * 
	 * fillChar:(设置填充字符). <br/>
	 * 
	 * @param str 原字符
	 * @param fill 填充字符
	 * @param digit 填充后总位数
	 * @param startOrend 填充在原字符首尾(1,-1) 1:字首填充；2:字尾填充
	 * @return
	 * @throws Exception
	 * @since 1.0
	 */
	public static String fillChar(String str, String fill, int digit, int startOrend) throws Exception {
		if (!(str.length() > digit)) {
			int slength = str.length();
			int i = digit - slength;
			StringBuffer fillStr = new StringBuffer();
			for (int x = 0; x < i; x++)
				fillStr.append(fill);
			if (startOrend >= 0)
				return fillStr + str;
			else
				return str + fillStr;
		} else {
			throw new Exception("fillCharacter Exception");
		}
	}

	/**
	 * 
	 * trimRight:(去除右边多余的空格). <br/>
	 * 
	 * @param value 待去右边空格的字符串
	 * @return 去右边空格的字符串
	 * @since 1.0
	 */
	public static String trimRight(String value) {
		String result = value;
		if (result == null)
			return result;
		char ch[] = result.toCharArray();
		int endIndex = -1;
		for (int i = ch.length - 1; i > -1; i--) {
			if (Character.isWhitespace(ch[i])) {
				endIndex = i;
			} else {
				break;
			}
		}
		if (endIndex != -1) {
			result = result.substring(0, endIndex);
		}
		return result;
	}

	/**
	 * 
	 * trimLeft:(去除左边多余的空格). <br/>
	 * 
	 * @param value 待去左边空格的字符串
	 * @return 去掉左边空格后的字符串
	 * @since 1.0
	 */
	public static String trimLeft(String value) {
		String result = value;
		if (result == null)
			return result;
		char ch[] = result.toCharArray();
		int index = -1;
		for (int i = 0; i < ch.length; i++) {
			if (Character.isWhitespace(ch[i])) {
				index = i;
			} else {
				break;
			}
		}
		if (index != -1) {
			result = result.substring(index + 1);
		}
		return result;
	}

	/**
	 * 
	 * combineStringArray:(将字符串数组使用指定的分隔符合并成一个字符串). <br/>
	 * 
	 * @param array 字符串数组
	 * @param delim 分隔符，为null的时候使用""作为分隔符（即没有分隔符）
	 * @return 合并后的字符串
	 * @since 1.0
	 */
	public static String combineStringArray(String[] array, String delim) {
		int length = array.length - 1;
		if (delim == null) {
			delim = "";
		}
		StringBuffer result = new StringBuffer(length * 8);
		for (int i = 0; i < length; i++) {
			result.append(array[i]);
			result.append(delim);
		}
		result.append(array[length]);
		return result.toString();
	}

	/**
	 * 
	 * contains:(字符串数组中是否包含指定的字符串). <br/>
	 * 
	 * @param strings 字符串数组
	 * @param string 字符串
	 * @param caseSensitive 是否大小写敏感
	 * @return 包含时返回true，否则返回false
	 * @since 1.0
	 */
	public static boolean contains(String[] strings, String string, boolean caseSensitive) {
		for (int i = 0; i < strings.length; i++) {
			if (caseSensitive == true) {
				if (strings[i].equals(string)) {
					return true;
				}
			} else {
				if (strings[i].equalsIgnoreCase(string)) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 
	 * lowerWord:(将一个字符串由驼峰式命名变成分割符分隔单词). <br/>
	 * eg: lowerWord("helloWorld", '-') => "hello-world"
	 * 
	 * @param cs 字符串
	 * @param c 分隔符
	 * @return 转换后字符串
	 * @since 1.0
	 */
	public static String lowerWord(CharSequence cs, char c) {
		StringBuilder sb = new StringBuilder();
		int len = cs.length();
		for (int i = 0; i < len; i++) {
			char ch = cs.charAt(i);
			if (Character.isUpperCase(ch)) {
				if (i > 0)
					sb.append(c);
				sb.append(Character.toLowerCase(ch));
			} else {
				sb.append(ch);
			}
		}
		return sb.toString();
	}

	/**
	 * 
	 * upperWord:(将一个字符串某一个字符后面的字母变成大写). <br/>
	 * eg: upperWord("hello-world", '-') => "helloWorld"
	 * 
	 * @param cs 字符串
	 * @param c 分隔符
	 * @return 转换后字符串
	 * @since 1.0
	 */
	public static String upperWord(CharSequence cs, char c) {
		StringBuilder sb = new StringBuilder();
		int len = cs.length();
		for (int i = 0; i < len; i++) {
			char ch = cs.charAt(i);
			if (ch == c) {
				do {
					i++;
					if (i >= len)
						return sb.toString();
					ch = cs.charAt(i);
				} while (ch == c);
				sb.append(Character.toUpperCase(ch));
			} else {
				sb.append(ch);
			}
		}
		return sb.toString();
	}

	/**
	 * 字符串首字母转大写
	 * @param str
	 * @return
	 */
	public static String firstLetterToUpper(String str) {
		char[] array = str.toCharArray();
		if (array[0] >= 'a' && array[0] <= 'z') {
			array[0] -= 32;
		}
		return String.valueOf(array);
	}

	/**
	 * 字符串首字母转小写
	 * @param str
	 * @return
	 */
	public static String firstLetterToLower(String str) {
		char[] array = str.toCharArray();
		if (array[0] >= 'A' && array[0] <= 'Z') {
			array[0] += 32;
		}
		return String.valueOf(array);
	}

	/**
	 * 
	 * removeHtmlTags:(根据传入的内容，去掉所有html标签). <br/>
	 * 
	 * @param htmlSource
	 * @return String
	 * @since 1.0
	 */
	public static String removeHtmlTags(String htmlSource) {
		return htmlSource.replaceAll("\\<.*?>", "");
	}

	/**
	 * 
	 * removeScript:(去掉script). <br/>
	 * 
	 * @param htmlSource
	 * @return String
	 * @since 1.0
	 */
	public static String removeScript(String htmlSource) {
		return htmlSource.replaceAll("\\<script.*?/script>", "");
	}

	/**
	 * 
	 * removeHreflink:(去除超链接). <br/>
	 * 
	 * @param htmlSource
	 * @return String
	 * @since 1.0
	 */
	public static String removeHreflink(String htmlSource) {
		htmlSource = htmlSource.replaceAll("\\<a[^>]*>", "");
		htmlSource = htmlSource.replaceAll("\\</a>", "");
		return htmlSource;
	}

	/**
	 * 
	 * removeScriptAndHrefTags:(删除script标签及超链接). <br/>
	 * 
	 * @param htmlSource
	 * @return String
	 * @since 1.0
	 */
	public static String removeScriptAndHrefTags(String htmlSource) {
		htmlSource = removeScript(htmlSource);
		htmlSource = removeHreflink(htmlSource);
		return htmlSource;
	}

	/**
	 * 在字符串中替换html标记所用的六个特殊字符：& \ " ' &lt; &gt;
	 * 
	 * @param str
	 * @return
	 */
	public static String htmlEncode(String str) {
		if (null == str) {
			return null;
		}
		String sTemp = str;
		sTemp = sTemp.replace("&", "&amp;");
		sTemp = sTemp.replace("\"", "&quot;");
		sTemp = sTemp.replace("'", "&#039;");
		sTemp = sTemp.replace("<", "&lt;");
		sTemp = sTemp.replace(">", "&gt;");
		return sTemp;
	}

	/**
	 * 
	 * text:(获取html文档中的文本 并仅提取文本中的前maxLength个 超出部分使用……补充). <br/>
	 * 
	 * @param html
	 * @param maxLength
	 * @return String
	 * @since 1.0
	 */
	public static String text(String html, int maxLength) {
		String text = removeHtmlTags(html);
		if (text.length() <= maxLength) {
			return text;
		}
		return text.substring(0, maxLength) + "……";
	}

	/**
	 * 
	 * substringBeforeLast:(根据指定的分隔符，从源字符串查找到最后一个分隔符，然后返回此分隔符前面的内容，如果找不到此分隔符则返回原字符串). <br/>
	 * 
	 * @param str
	 * @param separator
	 * @return String
	 * @since 1.0
	 */
	public static String substringBeforeLast(String str, String separator) {
		if ((str == null) || (separator == null) || (str.length() == 0) || (separator.length() == 0)) {
			return str;
		}

		int pos = str.lastIndexOf(separator);

		if (pos == -1) {
			return str;
		}

		return str.substring(0, pos);
	}

	/**
	 * 
	 * startsWithIgnoreCase:(判断开始部分是否与参数二相同。不区分大小写 ). <br/>
	 * 
	 * @param str
	 * @param prefix
	 * @return boolean
	 * @since 1.0
	 */
	public static boolean startsWithIgnoreCase(String str, String prefix) {
		return startsWith(str, prefix, true);
	}

	private static boolean startsWith(String str, String prefix, boolean ignoreCase) {
		if (str == null || prefix == null) {
			return (str == null && prefix == null);
		}
		if (prefix.length() > str.length()) {
			return false;
		}
		return str.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
	}

	/**
	 * 
	 * subString:(从原始字符串中，取得从start字符串开始但不包括start字符串，到end字符串为止其中所有的字符). <br/>
	 * eg : str= 'aabbccddee',start='bb',end='ee',则此时结果为'ccdd'。 开始及结束字符串必须存在，否则就报错。
	 * 
	 * @param src 源字符串
	 * @param start 开始字符串
	 * @param end 结尾字符串
	 * @return 开始字符串到结尾字符串的中间字符串
	 * @since 1.0
	 */
	public static String subString(String src, String start, String end) {
		src = src.substring(src.indexOf(start)).substring(start.length());
		if (end != null) {
			src = src.substring(0, src.indexOf(end));
		}
		return src;
	}

	/**
	 * 
	 * getListFromStart2End:(从给定的内容content中获取给定的start字符串到end字符串的所有内容，其中start和end的配对可以是多处，最终以List结果返回). <br/>
	 * eg: 给定的内容content为：adfadfsdfasBBttttCCxaafdsfdsBBddadfasfsfdCCxxxx，<br>
	 * start为:BB<br>
	 * end为：CC<br>
	 * 则返回的list结果包括两条记录：tttt 和 ddadfasfsfd.<br>
	 * 在获取时，end字符串所处的位置一定要大于start所处的位置，否则不以处理，默认来配对不成功，跳出处理的循环。
	 * 
	 * @param content 待获取回复的内容
	 * @param start 一个回复的开始分隔字符串
	 * @param end 一个回复的结束分隔字符串
	 * @param isFirstMainContent 第一项是否主内容，如论坛的内容和回复的分隔符都是一样的，此时在这个址为true的情况下，第一项不做为后回复，后面的才做为回复
	 * @return List<String>
	 * @since 1.0
	 */
	public static List<String> getListFromStart2End(String content, String start, String end,
			boolean isFirstMainContent) {
		List<String> replysList = new ArrayList<String>();
		if (content.indexOf(start) < 0) {
			return replysList;
		}
		int index_start = -1;
		int num = 1;
		while ((index_start = content.indexOf(start)) > 0) {
			content = content.substring(index_start);
			int index_end = content.indexOf(end);
			if (index_end > 0) {
				String reply = subString(content, start, end);
				if (!isFirstMainContent || (isFirstMainContent && num > 1)) {
					replysList.add(reply);
				}
				content = content.substring(content.indexOf(end) + end.length());
			} else {
				break;
			}
			num++;
		}
		return replysList;
	}

	/**
	 * 
	 * checkSubPattern:(找出含？的字符串). <br/>
	 * 
	 * @param src
	 * @param begin
	 * @param pat
	 * @return int
	 * @since 1.0
	 */
	private static int checkSubPattern(String src, int begin, String pat) {
		boolean isFound = true;
		if (src.length() - begin < pat.length()) {
			return -1;
		}

		for (int i = begin; i < src.length() - pat.length() + 1; i++) {
			for (int j = 0; j < pat.length(); j++) {
				if (pat.charAt(j) != '?' && src.charAt(i + j) != pat.charAt(j)) {
					isFound = false;
					break;
				}
				isFound = true;
			}

			if (isFound) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * 
	 * isMatching:(通配符“?”，“*”的字符串匹配). <br/>
	 * 
	 * @param src 源字符串
	 * @param pat 可包含通配符的字符串表达示
	 * @return boolean
	 * @since 1.0
	 */
	public static boolean isMatching(String src, String pat) {
		String[] sub_p = pat.split("\\*");
		int begin = 0;

		for (int i = 0; i < sub_p.length; i++) {
			begin = checkSubPattern(src, begin, sub_p[i]);
			if (begin == -1) {
				return false;
			}
			if (i == 0 && pat.charAt(i) != '*' && begin != 0) {
				return false;
			}
			if ((i == sub_p.length - 1) && pat.charAt(i) != '*' && begin != (src.length() - sub_p[i].length())) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 是否存在特殊字符 中文 英文 才符合 其他不符合
	 * 
	 * @param inputInfo
	 * @return
	 */
	public static boolean IsSpecialCharacters(String inputInfo) {
		String regex = "^[a-zA-Z\u4e00-\u9fa5\u3400-\u4DBF\\s]+$";
		return inputInfo.matches(regex);
	}

	/**
	 * str是否有长度
	 * @param str
	 * @return
	 */
	public static boolean hasLength(String str) {
		return (str != null && str.length() > 0);
	}

	/**
	 * str是否有长度(去空格判断)
	 * @param str
	 * @return
	 */
	public static boolean hasLengthWithTrim(String str) {
		if (str != null) {
			str = str.trim();
		}
		return (str != null && str.length() > 0);
	}

	/**
	 * str是否为空
	 * @param str
	 * @return
	 */
	public static boolean isNullOrBlank(String str) {
		if (str == null) {
			return true;
		} else if (str.equals("")) {
			return true;
		} else {
			return false;
		}
	}

	private static final char SEPARATOR = '_';

	private static final String CHARSET_NAME = "UTF-8";

	/**
	 * 转换为字节数组
	 * 
	 * @param str
	 * @return
	 */
	public static byte[] getBytes(String str) {
		if (str != null) {
			try {
				return str.getBytes(CHARSET_NAME);
			} catch (UnsupportedEncodingException e) {
				return null;
			}
		} else {
			return null;
		}
	}

	/**
	 * 转换为字节数组
	 * @return
	 */
	public static String toString(byte[] bytes) {
		try {
			return new String(bytes, CHARSET_NAME);
		} catch (UnsupportedEncodingException e) {
			return EMPTY;
		}
	}

	/**
	 * 是否包含字符串
	 * 
	 * @param str 验证字符串
	 * @param strs 字符串组
	 * @return 包含返回true
	 */
	public static boolean inString(String str, String... strs) {
		if (str != null) {
			for (String s : strs) {
				if (str.equals(trim(s))) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 替换掉HTML标签方法
	 */
	public static String replaceHtml(String html) {
		if (isBlank(html)) {
			return "";
		}
		String regEx = "<.+?>";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(html);
		String s = m.replaceAll("");
		return s;
	}

	/**
	 * 替换为手机识别的HTML，去掉样式及属性，保留回车。
	 * 
	 * @param html
	 * @return
	 */
	public static String replaceMobileHtml(String html) {
		if (html == null) {
			return "";
		}
		return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>");
	}

	/**
	 * 缩略字符串（不区分中英文字符）
	 * 
	 * @param str 目标字符串
	 * @param length 截取长度
	 * @return
	 */
	public static String abbr(String str, int length) {
		if (str == null) {
			return "";
		}
		try {
			StringBuilder sb = new StringBuilder();
			int currentLength = 0;
			for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) {
				currentLength += String.valueOf(c).getBytes("GBK").length;
				if (currentLength <= length - 3) {
					sb.append(c);
				} else {
					sb.append("...");
					break;
				}
			}
			return sb.toString();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 转换为Double类型
	 */
	public static Double toDouble(Object val) {
		if (val == null) {
			return 0D;
		}
		try {
			return Double.valueOf(trim(val.toString()));
		} catch (Exception e) {
			return 0D;
		}
	}

	/**
	 * 转换为Float类型
	 */
	public static Float toFloat(Object val) {
		return toDouble(val).floatValue();
	}

	/**
	 * 转换为Long类型
	 */
	public static Long toLong(Object val) {
		return toDouble(val).longValue();
	}

	/**
	 * 转换为Integer类型
	 */
	public static Integer toInteger(Object val) {
		return toLong(val).intValue();
	}

	/**
	 * 驼峰命名法工具
	 * 
	 * @return toCamelCase("hello_world") == "helloWorld" toCapitalizeCamelCase("hello_world") == "HelloWorld"
	 *         toUnderScoreCase("helloWorld") = "hello_world"
	 */
	public static String toCamelCase(String s) {
		if (s == null) {
			return null;
		}

		s = s.toLowerCase();

		StringBuilder sb = new StringBuilder(s.length());
		boolean upperCase = false;
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);

			if (c == SEPARATOR) {
				upperCase = true;
			} else if (upperCase) {
				sb.append(Character.toUpperCase(c));
				upperCase = false;
			} else {
				sb.append(c);
			}
		}

		return sb.toString();
	}

	/**
	 * 驼峰命名法工具
	 * 
	 * @return toCamelCase("hello_world") == "helloWorld" toCapitalizeCamelCase("hello_world") == "HelloWorld"
	 *         toUnderScoreCase("helloWorld") = "hello_world"
	 */
	public static String toCapitalizeCamelCase(String s) {
		if (s == null) {
			return null;
		}
		s = toCamelCase(s);
		return s.substring(0, 1).toUpperCase() + s.substring(1);
	}

	/**
	 * 驼峰命名法工具
	 * 
	 * @return toCamelCase("hello_world") == "helloWorld" toCapitalizeCamelCase("hello_world") == "HelloWorld"
	 *         toUnderScoreCase("helloWorld") = "hello_world"
	 */
	public static String toUnderScoreCase(String s) {
		if (s == null) {
			return null;
		}

		StringBuilder sb = new StringBuilder();
		boolean upperCase = false;
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);

			boolean nextUpperCase = true;

			if (i < (s.length() - 1)) {
				nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
			}

			if ((i > 0) && Character.isUpperCase(c)) {
				if (!upperCase || !nextUpperCase) {
					sb.append(SEPARATOR);
				}
				upperCase = true;
			} else {
				upperCase = false;
			}

			sb.append(Character.toLowerCase(c));
		}

		return sb.toString();
	}

	/**
	 * 如果不为空，则设置值
	 * 
	 * @param target
	 * @param source
	 */
	public static void setValueIfNotBlank(String target, String source) {
		if (isNotBlank(source)) {
			target = source;
		}
	}

	/**
	 * 转换为JS获取对象值，生成三目运算返回结果
	 * 
	 * @param objectString 对象串 例如：row.user.id 返回：!row?'':!row.user?'':!row.user.id?'':row.user.id
	 */
	public static String jsGetVal(String objectString) {
		StringBuilder result = new StringBuilder();
		StringBuilder val = new StringBuilder();
		String[] vals = split(objectString, ".");
		for (int i = 0; i < vals.length; i++) {
			val.append("." + vals[i]);
			result.append("!" + (val.substring(1)) + "?'':");
		}
		result.append(val.substring(1));
		return result.toString();
	}

	/**
	 * 将double类型数据转换为百分比格式，并保留小数点前IntegerDigits位和小数点后FractionDigits位
	 * @param d
	 * @param IntegerDigits
	 * @param FractionDigits
	 * @return
	 */
	public static String getPercentFormat(double d, int IntegerDigits, int FractionDigits) {
		NumberFormat nf = NumberFormat.getPercentInstance();
		nf.setMaximumIntegerDigits(IntegerDigits);// 小数点前保留几位
		if (d == 1L || d == 0L)
			FractionDigits = 0;
		nf.setMinimumFractionDigits(FractionDigits);// 小数点后保留几位
		String str = nf.format(d);
		return str;
	}

	/**
	 * @Description: 将任何单号->截取为【订单单号】
	 * @date : 2019年1月26日 下午5:40:17 
	 * @author: zChuang
	 * @param no
	 * @return
	 */
	public final static String cutToOrderNo(String no) {
		if (no == null)
			return null;
		Pattern p = Pattern.compile("(([A-Za-z]+)(\\d+))");
		Matcher m = p.matcher(no);
		m.find();
		try {
			return m.group(1);
		} catch (Exception e) {
		}
		return no;
	}
	
	/**
	 * @Description: 在一个字符串中查找某个子字符串出现的次数
	 * @date : 2020年1月10日 上午10:02:51 
	 * @author: zChuang
	 * @param str
	 * @param sToFind
	 * @return 次数
	 */
	public final static int countContains(String str, String sToFind) {
		int num = 0;
		while (str.contains(sToFind)) {
			str = str.substring(str.indexOf(sToFind) + sToFind.length());
			num++;
		}
		return num;
	}

	/**
	 *  @Author Dreamer(805592978@qq.com)
	 *  @Description 获取客户料号
	 *  @Date 2020/4/2 19:44
	 *  @Version 1.0
	 */
	public static <T> String getStringAndJoin(List<T> materials, Function<T, String> function) {
		String tempString = materials.parallelStream().map(function).filter(StringUtil::isNotEmpty).distinct().collect(Collectors.joining("-"));
		return StringUtil.isEmpty(tempString) ? "" : tempString.replaceAll(",","-");
	}
}
